package cn.demoncat.util.mybatis.util;

import cn.demoncat.util.lang.fn.Callback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 描述：事务操作
 *
 * @author 延晓磊
 *
 * @since 2017年3月23日
 */
@ConditionalOnClass(name = "org.springframework.jdbc.datasource.DataSourceTransactionManager")
@Component
public class TransactionUtil {

	@Autowired
	private PlatformTransactionManager platformTransactionManager;
	@Autowired
	private TransactionDefinition transactionDefinition;

	private static final Logger LOG = LoggerFactory.getLogger(TransactionUtil.class);

	/**
	 * 功能描述：主动回滚事务
	 *
	 * 注：默认由Spring管理事务(注解或配置的方法)，在RuntimeException时回滚，而在已检查Exception或try-catch时不会回滚
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年3月23日
	 */
	public static void rollback() {
		try {
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		} catch (Exception e) {
			LOG.warn("事务回滚失败", e);
		}

	}

	/**
	 * 功能描述：设置回滚事务的保存点
	 *
	 * 注：默认在事务完成时自动释放，可以手动或通过回滚到该保存点的方式释放
	 *
	 * @author 延晓磊
	 * @return 
	 *
	 * @since 2017年3月23日
	 */
	public static Object savePoint() {
		try {
			return TransactionAspectSupport.currentTransactionStatus().createSavepoint();
		} catch (Exception e) {
			LOG.warn("设置事务回滚点失败", e);
			return null;
		}
	}

	/**
	 * 功能描述：回滚事务至保存点
	 *
	 * 注：回滚到该保存点会释放保存点
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年3月23日
	 */
	public static void rollbackPoint(Object savePoint) {
		if (savePoint != null) {
			try {
				TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
			} catch (Exception e) {
				LOG.warn("事务回滚失败", e);
			}
		}
	}

	/**
	 * 功能描述：释放事务保存点
	 *
	 * 注：释放保存点，如果回滚将返回至事务初始
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年3月23日
	 */
	public static void releasePoint(Object savePoint) {
		if (savePoint != null) {
			try {
				TransactionAspectSupport.currentTransactionStatus().releaseSavepoint(savePoint);
			} catch (Exception e) {
				LOG.warn("释放事务回滚点失败", e);
			}
		}
	}

	/**
	 * 当前事务提交时回调
	 * 
	 * @param task
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月20日
	 */
	public static void afterCommit(Callback task) {
		// 有事务
		if (TransactionUtil.hasTransaction()) {
			// 注册事务同步操作，到线程事务同步管理器
			TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
				@Override
				public void afterCommit() {
					// 事务提交后的操作回调
					task.call();
				}
			});
		}else {
			// 无事务
			task.call();
		}
	}

	/**
	 * 当前事务提交/回滚时回调
	 *
	 * @param task	回调方法：0无事务，1提交，2回滚，3系统异常
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年1月20日
	 */
	public static void afterCompletion(Consumer<Integer> task) {
		// 有事务
		if (TransactionUtil.hasTransaction()) {
			// 注册事务同步操作，到线程事务同步管理器
			TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
				@Override
				public void afterCompletion(int status) {
					// 事务提交/回滚后的操作回调
					task.accept(status + 1);
				}
			});
		}else {
			// 无事务
			task.accept(0);
		}
	}

	/**
	 * 获取当前事务隔离级别
	 * 
	 * @see org.springframework.transaction.annotation.Isolation
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月20日
	 */
	public static Integer getIsolation() {
		return TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
	}
	
	/**
	 * 判断当前是否有真实的事务活动
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月20日
	 */
	public static boolean hasActualTransaction() {
		return TransactionSynchronizationManager.isActualTransactionActive();
	}
	
	/**
	 * 判断当前线程是否有事务活动
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月20日
	 */
	public static boolean hasTransaction() {
		return TransactionSynchronizationManager.isSynchronizationActive();
	}

	/**
	 * 开启手动事务
	 *
	 * @param task	业务操作
	 *
	 * @author 延晓磊
	 * @since 2022年08月17日
	 */
	public void transaction(Callback task){
		// 开启事务
		TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
		try {
			// 执行业务
			task.call();
			// 提交事务
			platformTransactionManager.commit(transaction);
		}catch (RuntimeException e){
			// 回滚事务
			platformTransactionManager.rollback(transaction);
			LOG.warn("业务执行失败，事务回滚", e);
			throw e;
		}
	}

	/**
	 * 开启手动事务
	 *
	 * @param task	业务操作
	 * @return 业务结果
	 *
	 * @author 延晓磊
	 * @since 2022年08月17日
	 */
	public <T>T transaction(Supplier<T> task){
		// 开启事务
		TransactionStatus transaction = platformTransactionManager.getTransaction(transactionDefinition);
		T result;
		try {
			// 执行业务
			result = task.get();
			// 提交事务
			platformTransactionManager.commit(transaction);
		}catch (RuntimeException e){
			// 回滚事务
			platformTransactionManager.rollback(transaction);
			LOG.warn("业务执行失败，事务回滚", e);
			throw e;
		}
		return result;
	}
}
